/*
 * Copyright 2016 Kejun Xia
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.shipdream.lib.ohos.mvc;

import com.shipdream.lib.ohos.mvc.event.bus.EventBus;
import com.shipdream.lib.ohos.mvc.event.bus.annotation.EventBusV;
import com.shipdream.lib.poke.Graph;
import com.shipdream.lib.poke.exception.PokeException;
import com.shipdream.lib.poke.util.ReflectUtils;

import ohos.agp.window.dialog.CommonDialog;
import ohos.app.Context;

import javax.inject.Inject;
import java.lang.reflect.InvocationTargetException;

/**
 * Abstract class for dialogs. Don't use it as a normal fragment but only for Dialog. To share logic
 * for similar dialog and fragment use shared controller.
 *
 * @param <CONTROLLER> The class type for the controller of this dialog
 */
public abstract class MvcDialog<CONTROLLER extends Controller> extends CommonDialog
        implements UiView {

    private static final String TAG = "MvcDialog";

    @Inject
    @EventBusV
    private EventBus eventBusV;

    protected CONTROLLER controller;

    public MvcDialog(Context context) {
        super(context);
    }

    protected abstract Class<CONTROLLER> getControllerClass();

    private Graph.Monitor graphMonitor;

    /**
     * Show dialog.
     *
     * @param dialogClass dialogClass
     */
    public static void show(Class<? extends MvcDialog> dialogClass) {
        MvcDialog dialogFragment = null;
        if (dialogFragment == null) {
            try {
                dialogFragment = new ReflectUtils.newObjectByType<>(dialogClass).newInstance();
                dialogFragment.show();
            } catch (NoSuchMethodException e) {
                Log.e(TAG, e.getMessage());
            } catch (IllegalAccessException e) {
                Log.e(TAG, e.getMessage());
            } catch (InvocationTargetException e) {
                Log.e(TAG, e.getMessage());
            } catch (InstantiationException e) {
                Log.e(TAG, e.getMessage());
            }
        }
    }

    @Override
    protected void onCreate() {
        super.onCreate();
        graphMonitor = new Graph.Monitor() {
            @Override
            public void onInject(Object target) {
                if (controller != null && target == MvcDialog.this) {
                    controller.view = MvcDialog.this;
                }
            }

            @Override
            public void onRelease(Object target) {
            }
        };
        Mvc.graph().registerMonitor(graphMonitor);

        try {
            controller = Mvc.graph().reference(getControllerClass(), null);
        } catch (PokeException e) {
            Log.e(TAG, e.getMessage());
        }
        Mvc.graph().inject(this);

        eventBusV.register(this);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Mvc.graph().unregisterMonitor(graphMonitor);
        eventBusV.register(this);
        Mvc.graph().release(this);
        try {
            Mvc.graph().dereference(controller, getControllerClass(), null);
        } catch (PokeException e) {
            Log.e(TAG, e.getMessage());
        }
    }

    /**
     * Handy method to post an event to other views directly. However, when possible, it's
     * recommended to post events from controllers to views to keep views' logic simple.
     *
     * @param event
     */
    protected void postEvent2V(Object event) {
        eventBusV.post(event);
    }

}
